
package financedata.historicalquotes;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.net.URL;
import java.net.URLConnection;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;


public class Money163Request implements IHistoryRequest {

    private final String mStockSymbol;

    private final Calendar from;
    private final Calendar to;

    private final Interval interval;

    private final static SimpleDateFormat sMoney163DateFmt;
    static {
        sMoney163DateFmt = new SimpleDateFormat("yyyyMMdd");
    }

    private static final String MONEY163_BASE_URL
            = "http://quotes.money.163.com/service/chddata.html";

    public static final Calendar DEFAULT_FROM = Calendar.getInstance();
    static {
        DEFAULT_FROM.add(Calendar.YEAR, -1);
    }
    public static final Calendar DEFAULT_TO = Calendar.getInstance();
    public static final Interval DEFAULT_INTERVAL = Interval.MONTHLY;

    Money163Request(String mStockSymbol) {
        this(mStockSymbol, DEFAULT_INTERVAL);
    }

    Money163Request(String mStockSymbol, Interval interval) {
        this.mStockSymbol   = mStockSymbol;
        this.interval = interval;

        this.from = DEFAULT_FROM;
        this.to   = DEFAULT_TO;
    }

    Money163Request(String mStockSymbol, Calendar from, Calendar to) {
        this(mStockSymbol, from, to, DEFAULT_INTERVAL);
    }

    Money163Request(String mStockSymbol, Calendar from, Calendar to, Interval interval) {
        this.mStockSymbol   = mStockSymbol;
        this.from     = from;
        this.to       = to;
        this.interval = interval;
    }

    Money163Request(String mStockSymbol, Date from, Date to) {
        this(mStockSymbol, from, to, DEFAULT_INTERVAL);
    }

    Money163Request(String mStockSymbol, Date from, Date to, Interval interval) {
        this(mStockSymbol, interval);
        this.from.setTime(from);
        this.to.setTime(to);
    }

    public List<HistoricalQuote> getResult() {
        
        List<HistoricalQuote> result = new ArrayList<HistoricalQuote>();
        String reqUrl = "noset";
        String currParseLine = null;
        int    parseIdx = 0;

        // http://quotes.money.163.com/service/chddata.html?code=0601398&start=20000720&end=20150508
        // http://quotes.money.163.com/service/chddata.html?code=0000001&start=19900101&end=20170317&fields=TOPEN;HIGH;LOW;TCLOSE;VATURNOVER;VOTURNOVER
        // http://quotes.money.163.com/service/chddata.html?code=0600651&start=19900101&end=20170317&fields=TOPEN;HIGH;LOW;TCLOSE;VATURNOVER;VOTURNOVER

        String startDate = null , endDate = null;
        try {
            Map<String, String> params = new LinkedHashMap<String, String>();
 
            params.put("code",  mStockSymbol);
            params.put("start", sMoney163DateFmt.format(from.getTime()));
            params.put("end",   sMoney163DateFmt.format(to.getTime()));
            params.put("fields",   "TOPEN;HIGH;LOW;TCLOSE;VATURNOVER;VOTURNOVER");


            reqUrl = MONEY163_BASE_URL + "?" + Utils.getURLParameters(params);
            //Utils.logger.log(Level.INFO, ("Sending request: " + reqUrl));

            // Get CSV
            URL request = new URL(reqUrl);
            URLConnection connection = request.openConnection();
            InputStreamReader is = new InputStreamReader(connection.getInputStream());
            BufferedReader br    = new BufferedReader(is);
            br.readLine(); // skip the first line

            // Parse CSV
            for(String line = br.readLine(); line != null; line = br.readLine()) {
                parseIdx++;
                currParseLine = Utils.unescape(line);
                String[] data = currParseLine.split(Utils.QUOTES_CSV_DELIMITER);

                if (null == startDate) {
                    startDate = data[0];
                } else {
                    endDate = data[0];
                }

                Calendar   calendarDate     = Utils.parseHistDate(data[0]);
                BigDecimal open     = new BigDecimal(data[3]);
                BigDecimal high     = new BigDecimal(data[4]);
                BigDecimal low      = new BigDecimal(data[5]);
                BigDecimal close    = new BigDecimal(data[6]);
                BigDecimal amount   = new BigDecimal(0.0);
                try {
                    amount = new BigDecimal(data[7]);
                } catch (NumberFormatException e) {
                }
                long       volume   = Long.valueOf(data[8]);

//                Utils.logger.log(Level.INFO, ("Parse CSV line: " + currParseLine));
//                Utils.logger.log(Level.INFO, ("Parsed result: " + new SimpleDateFormat("yyyyMMdd").format(calendarDate.getTime())
//                        + "," + open
//                        + "," + high
//                        + "," + low
//                        + "," + close
//                        + "," + yesClose
//                        + "," + volume
//                ));

                HistoricalQuote quote = new HistoricalQuote(this.mStockSymbol,
                        calendarDate, open, high,low, close, amount, volume);

                result.add(quote);
            }
//            Utils.logger.log(Level.INFO, ("ReqUrl:" + reqUrl + "\n Code:" + mStockSymbol
//                    + ", Count:" + parseIdx
//                    + ", startDate: " + startDate + ", endDate:" + endDate));
        } catch (Exception e) {
            Utils.logger.log(Level.SEVERE, ("Except Url=" + reqUrl + "\n currParseLine (" + currParseLine
                    + "), parseIdx=" + parseIdx
                    + ", startDate: " + startDate + ", endDate:" + endDate));
            Utils.logger.log(Level.SEVERE, e.toString(), e);
            return null;
        }
        return result;
    }

}
